﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Jenvin.Library.Threading
{
    /// <summary>
    /// 任务队列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TaskQueue : IDisposable
    {
        object locker = new object();
        Thread[] workers = null;
        Queue<AbstractTask> taskQ = new Queue<AbstractTask>();
        TaskContext m_taskContext = null;
        public TaskQueue(int workerCount, TaskContext context)
        {
            m_taskContext = context;
            workers = new Thread[workerCount];
            for (int i = 0; i < workerCount; i++)
            {
                (workers[i] = new Thread(Consume)).Start();
            }
        }
        protected internal TaskContext Context
        {
            get
            {
                return m_taskContext;
            }
        }
        public void Dispose()
        {
            foreach (Thread worker in workers)
            {
                EnqueueTask(null);
            }

            foreach (Thread worker in workers)
            {
                worker.Join();
            }
        }

        public void EnqueueTask(AbstractTask task)
        {
            lock (locker)
            {
                taskQ.Enqueue(task);
                this.m_taskContext.m_taskCount++;
                //Interlocked.Increment(ref this.m_taskContext.m_taskCount);
                Monitor.PulseAll(locker);
            }
        }

        private void Consume()
        {
            while (true)
            {
                //如果任务被取消
                if (this.m_taskContext.Exited)
                    return;

                AbstractTask task = null;
                lock (locker)
                {
                    while (taskQ.Count == 0) Monitor.Wait(locker);
                    task = taskQ.Dequeue();
                    this.m_taskContext.m_taskCount--;
                }
                if (task == null) return;
                try
                {
                    task.Execute();
                }
                catch (Exception ex)
                {
                    m_taskContext.LastError = ex;
                    throw ex;
                }
            }
        }
    }
}
